Skip to content

Fix crash caused by repeatedly cloning the same path hierarchy node #1220

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Merged
merged 12 commits into from
May 20, 2025

Conversation

d-ronnqvist
Copy link
Contributor

@d-ronnqvist d-ronnqvist commented May 16, 2025

Bug/issue #, if applicable: rdar://150706871&148247074

Summary

This primarily fixes a crash caused by repeatedly cloning the same path hierarchy node. (e161b2a)

Then if fixes additional crashes that were made more common due to cloned nodes (4187f62 and c12c7d1)

Seeing these changes in aggregate I would like to take some time to reorganize the path hierarchy initializer to better distinguish the expected code paths from the code paths that try to gracefully handle incomplete symbol graph files. However, I would want to cherry-pick these crash fixes into the 6.2 release and I'm not yet sure about the scope of the other code cleanup so I'd prefer to open a separate PR for that.

Dependencies

None.

Testing

Because most of these issues are related to unexpectedly incomplete symbol graph files it's fairly difficult to test this all the way from symbol graph generation. I could manually craft a symbol graph file that is based on one of the added unit tests, but I don't find that that would provide any more assurances than running the tests which the CI already does.

Checklist

Make sure you check off the following items. If they cannot be completed, provide a reason.

  • Added tests
  • Ran the ./bin/test script and it succeeded
  • Updated documentation if necessary

@d-ronnqvist
Copy link
Contributor Author

@swift-ci please test

@d-ronnqvist
Copy link
Contributor Author

@swift-ci please test

Copy link
Contributor

@binamaniar binamaniar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall looks good. I tried locally however I could never reproduce crash consistently but I can say with the change there is no crash.

// FIXME:
// This code path is both expected (when `knownDisambiguatedPathComponents` is non-nil) and unexpected (when the symbol graph is missing data or contains extra relationships).
// It would be good to restructure this code to better distinguish what's supported behavior and what's a best-effort attempt at gracefully handle invalid symbol graphs.
if let existing = parent.children[components.first!] {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

accessing parents.children without checking parens exists, may be the check is somewhere else ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand at al what this comment is referring to. The parent is not optional so it doesn't make any sense to check if it's nil. The compiler already guarantees that and trying to check using either if let or optional chaining would introduce a compiler error.

The only unwrapped optional value on this line of code is components.first! but that's not mentioned in your comment. Besides, it's safe to access the first element of the components array because this line of code is inside a loop over the components. If the execution enters the loop body it's because the components is non-empty (which makes it perfectly safe to unwrap the first component).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"accessing parents.children" I meant accessing its element by a specific value, and it is "components.first!" Yes you are right I didn't mention that but that's what I meant. I am just use to not using "!" whenever possible and hence my comment. I understand it would be safe to access it considering where it is used inside the loop over the components.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this index be using component instead of components.first!? It just looks like we're checking the first path component over and over instead of actually looking for successive children of the parent. Ditto for the assertion underneath this block, which i edited in #1212.

@d-ronnqvist
Copy link
Contributor Author

@swift-ci please test

Copy link
Contributor

@anferbui anferbui left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice one!

@binamaniar
Copy link
Contributor

binamaniar commented May 19, 2025

@d-ronnqvist Thank you for taking time to answer pr comments.

Copy link
Contributor

@QuietMisdreavus QuietMisdreavus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blocking the PR on my question because i feel like it significantly changes the implementation. We should add a test for nested children where the second layer is missing (not just the first) to ensure that all the path components are properly being checked.

// FIXME:
// This code path is both expected (when `knownDisambiguatedPathComponents` is non-nil) and unexpected (when the symbol graph is missing data or contains extra relationships).
// It would be good to restructure this code to better distinguish what's supported behavior and what's a best-effort attempt at gracefully handle invalid symbol graphs.
if let existing = parent.children[components.first!] {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this index be using component instead of components.first!? It just looks like we're checking the first path component over and over instead of actually looking for successive children of the parent. Ditto for the assertion underneath this block, which i edited in #1212.

@d-ronnqvist
Copy link
Contributor Author

@swift-ci please test

@d-ronnqvist d-ronnqvist dismissed QuietMisdreavus’s stale review May 20, 2025 10:43

The blocking feedback has been addressed in 2cdc04c

Copy link
Contributor

@QuietMisdreavus QuietMisdreavus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good with the new change. I left a couple comments on the tests but you can take it or leave it.

@d-ronnqvist
Copy link
Contributor Author

@swift-ci please test

@d-ronnqvist d-ronnqvist merged commit 471c1f1 into swiftlang:main May 20, 2025
2 checks passed
@d-ronnqvist d-ronnqvist deleted the repeated-node-cloning-crash branch May 20, 2025 16:25
d-ronnqvist added a commit to d-ronnqvist/swift-docc that referenced this pull request May 20, 2025
…wiftlang#1220)

* Don't repeatedly clone nodes that have already been cloned

rdar://150706871

* Fix unrelated code warning about unused local variable

* Fix unrelated list of symbols in other assertion message

* Avoid repetition in debug assertions

* Only create sparse nodes after processing all symbol graph files

* Try to find existing nodes before creating sparse nodes

rdar://148247074

* Remove trailing commas for compatibility before Swift 6.1

* Remove unintentional print statement

* Try to repair symbol graphs with deep hierarchies but no actual memberOf relationships

* Add additional test assertion about counterpart references
d-ronnqvist added a commit that referenced this pull request May 20, 2025
…1220) (#1226)

* Don't repeatedly clone nodes that have already been cloned

rdar://150706871

* Fix unrelated code warning about unused local variable

* Fix unrelated list of symbols in other assertion message

* Avoid repetition in debug assertions

* Only create sparse nodes after processing all symbol graph files

* Try to find existing nodes before creating sparse nodes

rdar://148247074

* Remove trailing commas for compatibility before Swift 6.1

* Remove unintentional print statement

* Try to repair symbol graphs with deep hierarchies but no actual memberOf relationships

* Add additional test assertion about counterpart references
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants